﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic.Core;
using Abp.Application.Services.Dto;
using Abp.Domain.Repositories;
using Abp.Extensions;
using Abp.Linq.Extensions;
using Abp.UI;
using Camc.OutsourceProcession.TaskProcess.Dto;
using Camc.OutsourceProcession.TaskProcess.Printer;
using Camc.OutsourceProcession.TaskProcess.Process;
using Camc.OutsourceProcession.TaskProcess.Request;
using Camc.OutsourceProcession.TaskProcess.TaskLine;
using Castle.Components.DictionaryAdapter;
using Microsoft.EntityFrameworkCore.Internal;

namespace Camc.OutsourceProcession.TaskProcess
{
	public class LineInstanceAppService: OutsourceProcessionAppServiceBase
	{
		private readonly IRepository<LineInstance, Guid> _lineInstanceRepository;
		private readonly IRepository<LineInstanceExecuteHistory, long> _lineInstanceExecuteHistoryRepository;
		private readonly IRepository<RequestBase, long> _requestBaseRepository;
		private readonly IRepository<NodeForInstance, long> _nodeForInstanceRepository;
		private readonly IRepository<LineTemplate, Guid> _lineTemplateRepository;


		public LineInstanceAppService(IRepository<LineInstance, Guid> lineInstanceRepository, IRepository<LineInstanceExecuteHistory, long> lineInstanceExecuteHistoryRepository, IRepository<RequestBase, long> requestBaseRepository, IRepository<NodeForInstance, long> nodeForInstanceRepository, IRepository<LineTemplate, Guid> lineTemplateRepository)
		{
			_lineInstanceRepository = lineInstanceRepository;
			_lineInstanceExecuteHistoryRepository = lineInstanceExecuteHistoryRepository;
			_requestBaseRepository = requestBaseRepository;
			_nodeForInstanceRepository = nodeForInstanceRepository;
			_lineTemplateRepository = lineTemplateRepository;
		}



		#region 管道操作

		public void PrintInstanceQr(string qrCode,string drawingCode,string quantity)
		{
		//	LabelPrint.Print(qrCode.ToString(), drawingCode, quantity);
		}

		public Guid ScanScreen(CreateInstanceInput input)
		{
			var defaultTemplateId = _lineTemplateRepository.GetAll().FirstOrDefault().Id;
			input.LineTemplateId = defaultTemplateId;

			var qrCode=  CreateLineInstance(input);

		//	LabelPrint.Print(qrCode.ToString(), input.ProductionDrawingCode, input.Quantity.ToString());

			return qrCode;
		}


		public Guid CreateLineInstance(CreateInstanceInput input)
		{
			if (_lineInstanceRepository.GetAll().Any(c => c.TaskKey == input.TaskKey))
			{
				
				// ReSharper disable once PossibleNullReferenceException
				return _lineInstanceRepository.GetAll().FirstOrDefault(c => c.TaskKey == input.TaskKey).Id;
			}
			else
			{
				var lineTemplate = _lineTemplateRepository.GetAllIncluding(c => c.TemplateNodeList).FirstOrDefault(c => c.Id == input.LineTemplateId);

				var newLineInstance = new LineInstance()
				{
					ProductionDrawingCode = input.ProductionDrawingCode,
					ProductionSpecial = input.ProductionSpecial,
					State = TaskLineState.进行,
					TaskModel = input.TaskModel,
					TaskKey = input.TaskKey,
					TemplateName = lineTemplate?.TemplateName,
					Quantity = input.Quantity,
					DeliveryTime = input.DeliveryTime
				};

				var instanceId = _lineInstanceRepository.InsertAndGetId(newLineInstance);

				if (lineTemplate.TemplateNodeList != null)
				{
					foreach (var node in lineTemplate.TemplateNodeList)
					{
						var nodeForTmp = new NodeForInstance()
						{
							NodeCode = node.NodeCode,
							NodeName = node.NodeName,
							OrderIndex = node.OrderIndex,
							WorkStationId = node.WorkStationId,
							LineInstanceId = instanceId
						};

						_nodeForInstanceRepository.Insert(nodeForTmp);
					}

					var initIndex = lineTemplate.TemplateNodeList.Min(c => c.OrderIndex);

					_lineInstanceExecuteHistoryRepository.Insert(new LineInstanceExecuteHistory()
					{
						OrderIndex = initIndex,
						LineInstanceId = instanceId,
						ExecutorAccount = GetCurrentUser().UserName,
						StartTime = DateTime.Now

					});
				}
				return instanceId;
			}
		}

		public void ExecuteProcess(ExecuteProcessInput input)
		{
			if (IsCanExe(input))
			{
				var instance = _lineInstanceRepository.Get(input.InstanceId);
				var lastExecute = instance.Historys.OrderByDescending(c => c.CreationTime).FirstOrDefault();
				if (lastExecute != null)
				{
					var newHistory = new LineInstanceExecuteHistory()
					{
						ExecutorAccount = GetCurrentUser().UserName,
						LineInstanceId = input.InstanceId,
						StartTime = DateTime.Now,
						OrderIndex = lastExecute.OrderIndex + 1
					};

					_lineInstanceExecuteHistoryRepository.Insert(newHistory);

					if (instance.InstanceNodeList.OrderByDescending(c => c.OrderIndex).FirstOrDefault()?.OrderIndex ==
						lastExecute.OrderIndex + 1)
					{
						instance.State = TaskLineState.完成;
					}
				}
			}
			else
			{
				throw new UserFriendlyException("不能在此工位扫描，请确认前置工序已完成。");

			}
		}

		public void GotoProcess(GotoProcessInput input)
		{
			var instance = _lineInstanceRepository.GetAllIncluding(c => c.InstanceNodeList,d=>d.Historys).FirstOrDefault(c => c.IsDeleted == false);

			var target = instance?.InstanceNodeList.FirstOrDefault(c => c.OrderIndex == input.OrderIndex);
			var lastExecute = instance?.Historys.OrderByDescending(c => c.CreationTime).FirstOrDefault();


			if (target != null)
			{
				if (target.OrderIndex <= lastExecute?.OrderIndex)
				{
					var newHistory = new LineInstanceExecuteHistory()
					{
						ExecutorAccount = GetCurrentUser().UserName,
						LineInstanceId = input.LineInstanceId,
						StartTime = DateTime.Now,
						OrderIndex = input.OrderIndex
					};
					_lineInstanceExecuteHistoryRepository.Insert(newHistory);
				}
				else
				{
					throw new UserFriendlyException("不能跳序执行！");
				}
			}
		}

		public void SetState(SetStateInut input)
		{
			var instance = _lineInstanceRepository.Get(input.InstanceId);
			instance.State = input.State;
		}

		private bool IsCanExe(ExecuteProcessInput input)
		{
			var instance = _lineInstanceRepository.GetAllIncluding(c=>c.InstanceNodeList,d=>d.Historys).FirstOrDefault(c=>c.IsDeleted==false && c.Id==input.InstanceId);

			if (instance?.State != TaskLineState.进行)
			{
				throw new UserFriendlyException("改任务无法执行，请处理后再执行！");
			}
			else
			{
				var lastExecute = instance.Historys.OrderByDescending(c => c.CreationTime).FirstOrDefault();

				if (lastExecute == null)
				{
					var firstNode = instance.InstanceNodeList.OrderBy(c => c.OrderIndex).FirstOrDefault();
					if (firstNode == null)
					{
						throw new UserFriendlyException("该工作没有工作节点，请核对！");
					}
					else
					{
						return firstNode.WorkStationId == input.WorkStationId;
					}
				}
				else
				{
					var index = instance.InstanceNodeList.OrderBy(c => c.OrderIndex)
						.IndexOf(instance.InstanceNodeList.FirstOrDefault(c => c.OrderIndex == lastExecute.OrderIndex) ?? throw new InvalidOperationException());

					var currentExe = instance.InstanceNodeList.OrderBy(c => c.OrderIndex).ToArray()[index+1];

					return currentExe.WorkStationId == input.WorkStationId;
				}
			}
		}

		public List<ComboboxItemDto> GetProcessOfExeForCombobox(Guid instanceId)
		{
			var instance = _lineInstanceRepository.GetAllIncluding(c=>c.InstanceNodeList,d=>d.Historys).FirstOrDefault(c=>c.Id==instanceId);
			var currentOrderIndex = 1;
			if (instance != null && instance.Historys != null)
			{
				// ReSharper disable once PossibleNullReferenceException
				currentOrderIndex = instance.Historys.OrderByDescending(c => c.OrderIndex).FirstOrDefault().OrderIndex;
			}

			var output = new List<ComboboxItemDto>();
			foreach (var node in instance.InstanceNodeList)
			{
				bool selected = node.OrderIndex == currentOrderIndex;
				output.Add(new ComboboxItemDto(node.OrderIndex.ToString(),node.NodeName));
			}

			return output;
		}



		#endregion


		#region 问题管理

		public PagedResultDto<GetAllRequestOutput> GetAllRequest(GetAllRequestInput input)
		{
			var query = _requestBaseRepository.GetAll();

			query = query.WhereIf(input.OnlyUntreated, c => c.Responder.IsNullOrWhiteSpace());

			var groupJoin = query.GroupJoin(_lineInstanceRepository.GetAll(),
				o => o.LineInstanceId,
				p => p.Id,
				(request, instance) => new GetAllRequestOutput
				{
					Id = request.Id,
					InstanceId = request.LineInstanceId,
					Model = instance.FirstOrDefault().TaskModel,
					DrawingCode= instance.FirstOrDefault().ProductionDrawingCode,
					CreationTime = request.CreationTime,
					RequesterId = request.RequesterId,
					Responder = request.Responder,
					RequestInfo = request.RequestInfo,
					RespondInfo = request.RespondInfo,
					RespondOperation = request.RespondOperation,
					RespondTime = request.RespondTime
				}
			);

			groupJoin = groupJoin
					.WhereIf(!input.FilterModel.IsNullOrWhiteSpace(), c => c.Model == input.FilterModel)
					.WhereIf(!input.FilterDrawingCode.IsNullOrWhiteSpace(),
						c => c.DrawingCode == input.FilterDrawingCode)
				;


			if (input.Sorting.IsNullOrWhiteSpace())
			{
				input.Sorting = "CreationTime desc";
			}

			var count = groupJoin.Count();

			var requestList = groupJoin
				.OrderBy(input.Sorting)
				.PageBy(input)
				.ToList();


			return new PagedResultDto<GetAllRequestOutput>(
				count,
				requestList
			);
		}

		public long AddRequest(AddRequestInput input)
		{
			SetState(new SetStateInut() { InstanceId = input.InstanceId, State = TaskLineState.暂停 });

			return _requestBaseRepository.InsertAndGetId(new RequestBase()
			{
				RequestInfo = input.RequestInfo,
				RequesterId = GetCurrentUser().UserName,
				LineInstanceId = input.InstanceId
			});
		}

		public void AddRespond(AddRespondInput input)
		{
			SetState(new SetStateInut() { InstanceId = input.InstanceId, State = TaskLineState.进行 });
			if (input.GotoIndex >= 0)
			{
				GotoProcess(new GotoProcessInput() { LineInstanceId = input.InstanceId, OrderIndex = input.GotoIndex });
			}

			var requestBase = _requestBaseRepository.FirstOrDefault(c => c.Id == input.RequestId);
			requestBase.RespondInfo = input.RespondInfo;
			requestBase.RespondOperation = $"跳转到第【{input.GotoIndex}】步。";
			requestBase.RespondTime = DateTime.Now;
			requestBase.Responder = GetCurrentUser().UserName;
		}

		#endregion


		#region 管道查询

		public PagedResultDto<GetLineInstanceForExecuteOutput> GetAllLineInstance(
			GetLineInstanceForExecuteInput input)
		{
			TaskLineState? state;

			if (input.StateValue.IsNullOrWhiteSpace())
			{
				state = null;
			}
			else
			{
				state = (TaskLineState)Enum.Parse(typeof(TaskLineState), input.StateValue);
			}


			var query = _lineInstanceRepository.GetAllIncluding(c=>c.InstanceNodeList,d=>d.Historys,e=>e.WorkingTeam).Where(c=>c.IsDeleted == false);

			query = query
					.WhereIf(!input.ProductionDrawingCode.IsNullOrWhiteSpace(),
						c => c.ProductionDrawingCode.Contains(input.ProductionDrawingCode.ToLower().Trim()))
					.WhereIf(!input.TaskModel.IsNullOrWhiteSpace(), c => c.TaskModel.Contains(input.TaskModel.ToLower().Trim()))
					.WhereIf(state != null, c => c.State == state)
					.WhereIf(!input.WorkingTeamId.IsNullOrWhiteSpace(), c => c.WorkingTeamId == Convert.ToInt32(input.WorkingTeamId))
					.WhereIf(!input.WorkStationId.IsNullOrWhiteSpace(), c =>
						c.Historys.OrderByDescending(d => d.CreationTime).FirstOrDefault().OrderIndex == c.InstanceNodeList
							.FirstOrDefault(e => e.WorkStationId == new Guid(input.WorkStationId)).OrderIndex)
				;

		

			if (input.Sorting.IsNullOrWhiteSpace())
			{
				input.Sorting = "CreationTime desc";
			}

			var count = query.Count();

			var lineInstances = query
				.OrderBy(input.Sorting)
				.PageBy(input)
				.ToList();

			var outputs = lineInstances.Select(c=> new GetLineInstanceForExecuteOutput()
			{
				CurrentStationName = c.InstanceNodeList.FirstOrDefault(d =>
						d.OrderIndex == c.Historys?.OrderByDescending(f => f.CreationTime).FirstOrDefault()?.OrderIndex)?
					.NodeName,
				ProductionDrawingCode = c.ProductionDrawingCode,
				ProductionSpecial = c.ProductionSpecial,
				Id = c.Id,
				StateDisplayText = c.State.ToString(),
				TaskModel = c.TaskModel,
				Quantity = c.Quantity,
				DeliveryTime = c.DeliveryTime,
				WorkingTeamName = c.WorkingTeam?.DisplayName,
				DurationString =
					(DateTime.Now - c.Historys?.OrderByDescending(f => f.CreationTime).FirstOrDefault()?.StartTime)?
					.TotalHours.ToString("f1")
			}).ToList();

			return new PagedResultDto<GetLineInstanceForExecuteOutput>(
				count,
				outputs
			);
		}

		#endregion

		
	}
}
